using System.Linq.Expressions;

namespace FastDevTemplate.Service.Interface.Base;

public interface IBaseCurdService<TEntity, in TKey, TEntityResultDto, TEntityGetDto, in TAddEntityDto,
    in TModifyEntityDto> :
    IBaseQueryService<TEntity, TKey, TEntityResultDto, TEntityGetDto>
    where TEntity : class, new()
    where TEntityResultDto : class
    where TEntityGetDto : class
    where TAddEntityDto : class
    where TModifyEntityDto : class
{
    #region Sync

    //Command
    public TEntityResultDto? Add(TAddEntityDto commandDto);
    public TEntityResultDto? Update(TKey id, TModifyEntityDto commandDto);
    public TEntityResultDto? Remove(TKey id);

    #endregion

    #region Async

    // Command
    public Task<TEntityResultDto?> AddAsync(TAddEntityDto commandDto);
    public Task<TEntityResultDto?> ModifyAsync(TKey id, TModifyEntityDto commandDto);
    public Task<TEntityResultDto?> RemoveAsync(TKey id);

    #endregion
}

public interface IBaseQueryService
    <TEntity, in TKey, TEntityResultDto, TEntityGetDto> :
    IBaseService
    where TEntity : class, new()
    where TEntityResultDto : class
    where TEntityGetDto : class
{
    public TEntityGetDto? GetById(TKey id);
    
    public IEnumerable<TEntityResultDto> GetSet(
        params Expression<Func<TEntity, bool>>[] filterExpression);

    public PageResultDto<TEntityResultDto> GetPage(int pageIndex, int pageSize,
        params Expression<Func<TEntity, bool>>[] filterExpression);

    public bool Exist(Expression<Func<TEntity, bool>> filterExpression);

    public Task<TEntityGetDto?> GetByIdAsync(TKey id);

    public Task<PageResultDto<TEntityResultDto>> GetPageAsync(int pageIndex, int pageSize,
        params Expression<Func<TEntity, bool>>[] filterExpression);

    // public Task<PageResultDto<TEntityResultDto>> GetPageAsync(int pageIndex, int pageSize,
    //     Func<TEntityResultDto, TEntityResultDto>? dtoForEch = null,
    //     params Expression<Func<TEntity, bool>>[] filterExpression);

    public Task<PageResultDto<TEntityResultDto>> GetPageAsync<TSortKey>(int pageIndex, int pageSize,
        Expression<Func<TEntity, TSortKey>> orderBy,
        bool isAscendingOrder = true,
        params Expression<Func<TEntity, bool>>[] filterExpression);

    public Task<IEnumerable<TEntityResultDto>> GetSetAsync(
        params Expression<Func<TEntity, bool>>[] filterExpression);

    public Task<IEnumerable<TEntityResultDto>> GetSetAsync(
        Func<TEntityResultDto, TEntityResultDto>? dtoForEch = null,
        params Expression<Func<TEntity, bool>>[] filterExpression);

    public Task<bool> ExistAsync(Expression<Func<TEntity, bool>> filterExpression);
}